﻿
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

#include "CmdRemoveNode.h"
#include "IElement.h"
#include "OwnerPtr.h"
#include "IDocument.h"
#include "ElementId.h"
#include "ISelection.h"
#include "IUiDocument.h"
#include "IDirectShape.h"
#include "UiCommonDialog.h"
#include "IGenericElement.h"
#include "GcmpCommandState.h"
#include "IUserTransaction.h"
#include "GraphicsNodeUtils.h"
#include "IElementModelShape.h"
#include "IPureGraphicsElement.h"
#include "IGraphicsElementShape.h"
#include "IUiDocumentViewManager.h"
#include "GcmpBuiltInCategoryUniIdentities.h"

#include "GRepCommandIds.h"
#include "CommandRegister.h"
#include "GRepProbe/GRepProbe.h"
#include "GRepProbe/GrepProbeDlg.h"
#include "GRepProbe/GNodeUtility.h"
#include "GRepProbe/ObjectBrowser.h"
#include "GRepProbe/GNodeWrapper.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

using namespace gcmp;
using namespace Sample;

REGISTER_COMMAND(CmdRemoveNode)

CmdRemoveNode::CmdRemoveNode()
    :CommandBase(ID_CMD_GREP_REMOVE_NODE), m_isRemoving(false)
{
}

bool CmdRemoveNode::IsEnabled() const
{
    if (m_isRemoving || !GcmpCommandState::IsInDocumentEnvironment())
    {
        return false;   // 避免删除中进入，会有野指针
    }

    GRepProbe* pGRepProbe = GRepProbe::Get();
    if (!pGRepProbe->IsValid())
    {
        return false;
    }

    // 确认GRep图形表达浏览器初始化过
    ObjectBrowser* objectBrowser = ObjectBrowser::Get();
    if (!objectBrowser) { return false; }

    // 确认GRep图形表达浏览器里有源图元的GRep信息
    IGraphicsNode_Wrapper* pGNodeWrapper = objectBrowser->GetGNodeWrapper();
    if (!pGNodeWrapper) { return false; }

    // 确认GRep图形表达浏览器里的源Grep是可以修改的，并且的包含源GRep不为空
    if (pGNodeWrapper->IsReadOnly()) { return false; }

    if (IGraphicsNode* pGNode = pGNodeWrapper->GetGraphicsNode())
    {
        // Edge和Face是Body的一部分，不能单独删除
        if (pGNode->GetType() == GraphicsNodeType::Edge || pGNode->GetType() == GraphicsNodeType::Face)
        {
            return false;
        }
        if (pGNodeWrapper->GetParent() == nullptr)
        {
            return false;
        }
        return true;
    }
    return false;
}

bool CmdRemoveNode::IsVisible() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

gcmp::OwnerPtr<gcmp::IAction> CmdRemoveNode::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDocViewMgr, L"获取UI文档视图管理器失败",L"GDMP",L"2024-03-30");
    IUiDocument* pUiDoc = pUiDocViewMgr->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDoc, L"获取UI文档失败",L"GDMP",L"2024-03-30");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"获取文档失败",L"GDMP",L"2024-03-30");

    ObjectBrowser* pObjectBrowser = ObjectBrowser::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pObjectBrowser, L"pObjectBrowser为空",L"GDMP",L"2024-03-30");

    // 获得图形表达浏览器中将要删除节点
    IGraphicsNode_Wrapper* pGNodeWrapperTarget = pObjectBrowser->GetGNodeWrapper();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGNodeWrapperTarget, L"pGNodeWrapperTarget为空",L"GDMP",L"2024-03-30");

    // 获得将要删除节点所属的集合节点
    IGraphicsNode* pGNodeTarget = pGNodeWrapperTarget->GetGraphicsNode();
    IGraphicsNode_Wrapper* pGNodeTargetParent = pGNodeWrapperTarget->GetParent();
    if (pGNodeTargetParent == nullptr) { return nullptr; }
    IGraphicsGroupBase* pGGroupTarget = quick_cast<IGraphicsGroupBase>(pGNodeTargetParent->GetGraphicsNode());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGGroupTarget, L"pGGroupTarget为空",L"GDMP",L"2024-03-30");

    ElementId idTarget = pGNodeWrapperTarget->GetElementId();
    IElement* pElementTarget = pDoc->GetElement(idTarget);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementTarget, L"pElementTarget为空",L"GDMP",L"2024-03-30");

    // 可以删除GRep的图元可以是IDirectShape或IPureGraphicsElement。如果都不是，则退出。
    IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElementTarget);
    IDirectShape* pDirectShape = nullptr;
    IPureGraphicsElement* pPGE = quick_cast<IPureGraphicsElement>(pElementTarget);
    if (pGenericElement)
    {
        pDirectShape = quick_cast<IDirectShape>(pGenericElement->GetExternalObject());
    }
    if ((pDirectShape == nullptr) && (pPGE == nullptr))
    {
        UiCommonDialog::ShowMessageBox(L"提示", L"图形表达探针树中的图元不是IDirectShape或IPureGraphicsElement，因此无法删除图形节点", (int)UiCommonDialog::ButtonType::Yes);
        return nullptr;
    }

    IGraphicsNode_Wrapper* pGRepWrapperTarget = pGNodeWrapperTarget->GetRootParent();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGRepWrapperTarget, L"pGRepWrapperTarget为空",L"GDMP",L"2024-03-30");
    OwnerPtr<IGraphicsElementShape> opTargetCachedGRep = TransferOwnership(pGRepWrapperTarget->GetCachedGRep());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opTargetCachedGRep, L"opTargetCachedGRep为空",L"GDMP",L"2024-03-30");

    // 图形表达探针树中对应的目标图元可能移动过，下面代码根据缓存的GRep和最新GRep的包围盒，将缓存GRep移动到最新位置
    {
        Box3d cachedTargetGRepBox = GraphicsNodeUtils::CalculateGraphicsNodeBoundingBox(pDoc, opTargetCachedGRep.get());

        const IElementModelShape* pTargetLatestModelShape = pElementTarget->GetElementModelShape();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pTargetLatestModelShape, L"pTargetLatestModelShape为空",L"GDMP",L"2024-03-30");
        const IGraphicsElementShape* pTargetLatestGRep = pTargetLatestModelShape->GetGraphicsElementShape();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pTargetLatestGRep, L"pTargetLatestGRep为空",L"GDMP",L"2024-03-30");
        Box3d targetLatestGRepBox = GraphicsNodeUtils::CalculateGraphicsNodeBoundingBox(pDoc, pTargetLatestGRep);

        DBG_WARN_UNLESS(!cachedTargetGRepBox.IsEmpty(), L"cachedTargetGRepBox为空",L"GDMP",L"2024-03-30");
        DBG_WARN_UNLESS(!targetLatestGRepBox.IsEmpty(), L"targetLatestGRepBox为空",L"GDMP",L"2024-03-30");

        Vector3d movedVector = (targetLatestGRepBox.GetCenter() - cachedTargetGRepBox.GetCenter());
        Matrix4d matrix;
        matrix.MakeTranslate(movedVector);
        opTargetCachedGRep->Transform(matrix);
    }

    OwnerPtr<IUserTransaction> opTransaction = IUserTransaction::Create(pDoc, L"删除GNode");
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opTransaction, L"opTransaction为空",L"GDMP",L"2024-03-30");
    m_isRemoving = true;

    // 删除图形节点
    pGGroupTarget->DeleteChild(pGNodeTarget);
    // 深克隆一份目标图元的GRep用于图形表达探针
    OwnerPtr<IGraphicsElementShape> opNewTargetCachedGRep = TransferOwnershipQuickCast<IGraphicsElementShape>(opTargetCachedGRep->Clone());

    // 根据目标图元是IPureGraphicsElement或IDirectShape去设置GRep
    if (pDirectShape)
    {
        pDirectShape->SetGraphicsElementShape(TransferOwnership(opTargetCachedGRep));
    }
    else if (pPGE)
    {
        IElementModelShape* pElemModelShape = pPGE->GetElementModelShape();
        pElemModelShape->SetGraphicsElementShape(TransferOwnership(opTargetCachedGRep));
    }

    opTransaction->Commit();

    // 图形表达探针浏览器清空
    pObjectBrowser->SetDataAndUpdate(nullptr);
    // 显示图形表达探针树窗口
    GrepProbeDlg* pGrepProbeDlg = GrepProbeDlg::GetOrCreate();
    pGrepProbeDlg->ShowDock();

    // 显示图形表达探针树显示添加过图形表达的新的GRep
    OwnerPtr<IGraphicsNode_Wrapper> opGNodeWrapper = GNodeUtility::CreateGNodeWrapperTree(pDoc, idTarget, opNewTargetCachedGRep.get(), opNewTargetCachedGRep.get(), false, nullptr);
    pGrepProbeDlg->SetDisplayData(TransferOwnership(opGNodeWrapper));
    pGrepProbeDlg->GetDisplayData()->CacheGRep(TransferOwnership(opNewTargetCachedGRep));
    m_isRemoving = false;
    return nullptr;
}

